package cn.elegent.lock.strategy.consul;

import com.ecwid.consul.v1.ConsulClient;
import com.ecwid.consul.v1.Response;
import com.ecwid.consul.v1.session.model.Session;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;


/**
 * 使用看门狗的方式监控锁 如果session存在则对其续命
 */
@Slf4j
public class ConsulWatchDog {

    private ConsulClient consulClient;

    public ConsulWatchDog(ConsulClient consulClient) {
        this.consulClient = consulClient;
    }

    public ConsulWatchDog() {
    }

    private volatile boolean flag = false;
    //sessionID    看门狗线程
    ConcurrentHashMap<String, ScheduledFuture> taskMap = new ConcurrentHashMap<>();

    /**
     * 由于系统的特点，使用的是具有延迟且循环功能的线程池
     */
    private static ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);

    public void watchSession(String sessionId,int ttlTime){
        if(sessionId!=null&&ttlTime>0){
            //ttl秒后执行第一次  间隔ttlTime秒后执行一次
            ScheduledFuture scheduledFuture = scheduledThreadPool.scheduleAtFixedRate(new Task(sessionId), ttlTime, ttlTime, TimeUnit.SECONDS);
            //将sessionid做为key 定时任务作为value存入ConcurrentHashMap中
            taskMap.put(sessionId,scheduledFuture);
            log.info("分布式锁看门狗开启，sessionId:{}",sessionId);
        }else{
            //什么也不做
            log.info("sessionId为NUll或ttl==0");
        }
    }

    /**
     * 监控线程池是否在执行的方法
     */
    class Task implements Runnable{

        private String sessionId;

        public Task(String sessionId) {
            this.sessionId = sessionId;
        }

        @Override
        public void run() {
            //每次触发的时候--重新刷新sessionId的时长
            //判断sessionId是否存在如果存在则表示业务未执行完 需要进行续命
            if(checkSessionId(sessionId)){
                //对其续命  kv->session进行续命操作 在原有的时长上+时长
                consulClient.renewSession(sessionId,null);//重新开始计时
                log.info("分布式锁续命，sessionId:{}",sessionId);
            }else{
                //如果业务释放-》看门狗线程需要回收资源
                //证明业务系统已经执行完 已经手动释放了锁 锁以不存在 关闭该开门狗
                //关闭看门狗定时任务
                taskMap.get(sessionId).cancel(true);//回收资源
                log.info("分布式锁看门狗关闭，sessionId:{}",sessionId);
                return;
            }
        }

        /**
         * 校验sessionId是否存在的代码
         * @param sessionId
         * @return
         */
        private boolean checkSessionId(String sessionId) {
            Response<Session> sessionInfo = consulClient.getSessionInfo(sessionId, null);
            if(sessionInfo.getValue()==null){
                return false;
            }else{
                return true;
            }
        }
    }
}

